using System;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using DiggThis.Properties;
using DiggThis.Utils;
using WindowsLive.Writer.Api;

namespace DiggThis.Forms
{
    public partial class DiggThisEditor : SmartContentEditor
    {
        #region Fields
        /// <summary>
        /// Connection between a <see cref="SmartContentEditor"/> object and its user interface context.
        /// Provides notification of inline image resizing and allows the editor to manipulate the status
        ///  bar of the Sidebar.
        /// </summary>
        private ISmartContentEditorSite editorSite;
        /// <summary>
        /// Flag to indicate whether or not this editor is initialized.
        /// </summary>
        private bool initialized = false;
        #endregion Fields

        #region Properties
        private static string ReadmeFile
        {
            get { return Assembly.GetExecutingAssembly().Location.Replace(".dll", ".rtf"); }
        }
        #endregion Properties

        #region Initialization
        /// <summary>
        /// Constructs a <see cref="DiggThisEditor"/> instance.
        /// </summary>
        public DiggThisEditor(ISmartContentEditorSite editorSite)
        {
            // Initialize all child components.
            InitializeComponent();
            // Track editor attributes.
            this.editorSite = editorSite;
            // Update the look of the ToolStrip.
            ToolStripManager.Renderer = new DiggThisRenderer();
        }
        #endregion Initialization

        #region Overrides
        /// <summary>
        /// Overriden to initializes control properties.
        /// </summary>
        /// <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            // Call the base implementation.
            base.OnLoad(e);
            // Set the title of the control.
            Text = Resources.DiggThisTitle;
        }
        /// <summary>
        /// Overriden to handle the update of the UI with currently selected smart content.
        /// </summary>
        protected override void OnSelectedContentChanged()
        {
            // Make sure we mark the editor as not completely initialized to prevent premature
            // processing of events.
            initialized = false;
            // Assign a text to the control.
            Text = Resources.DiggThisTitle;
            // Allow the base implementation to complete its work.
            base.OnSelectedContentChanged();
            // Update the UI with the values from the settings of the current or active
            // smart content.
            UpdateControlsWithSetting();
            // Indicate that this editor is now initialized.
            initialized = true;
        }
        #endregion Overrides

        #region Event Handlers

        #region Top Menu
        /// <summary>
        /// Saves the current settings as defaults.
        /// </summary>
        /// <param name="sender">Control causing the event.</param>
        /// <param name="e">Object containing details on the raised event.</param>
        private void btnSaveSettings_Click(object sender, EventArgs e)
        {
            // Persist the settings.
            DiggThisConfig.GetInstance(SelectedContent).Store();
        }
        /// <summary>
        /// Launches the supplied ReadMe file.
        /// </summary>
        /// <param name="sender">Control causing the event.</param>
        /// <param name="e">Object containing details on the raised event.</param>
        private void btnHelp_Click(object sender, EventArgs e)
        {
            try
            {
                Process.Start(ReadmeFile);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
        /// <summary>
        /// Launches the blog post detailing this plugin.
        /// </summary>
        /// <param name="sender">Control causing the event.</param>
        /// <param name="e">Object containing details on the raised event.</param>
        private void btnVisitMyBlog_Click(object sender, EventArgs e)
        {
            Process.Start("http://lvildosola.blogspot.com/2007/03/digg-this-plugin-for-windows-live.html");
        }
        #endregion Top Menu

        #region Form
        /// <summary>
        /// Event handler used to capture any changes to the editor.
        /// </summary>
        /// <param name="sender">Control causing the event.</param>
        /// <param name="e">Object containing details on the raised event.</param>
        private void ContentsChanged(object sender, EventArgs e)
        {
            // Only process any messages if properly initialized. Otherwise, the event will be raised prematurely.
            if (initialized)
            {
                // Determine if the sender is a TextBox instance.
                TextBox textBox = sender as TextBox;
                if (textBox != null)
                {
                    // Determine if the sender is the background color control and if so validate
                    // the color specified.
                    if ((textBox == tbBkgColor) && !IsValidCSSColor(tbBkgColor.Text))
                    {
                        // TODO: Find another way to prevent pasting invalid colors.
                        // If the color is not good, simply clear the control and don't allow it.
                        tbBkgColor.Text = string.Empty;
                        // Don't allow any further processing.
                        return;
                    }
                    // Update the status bar to display the number of characters allowed.
                    editorSite.UpdateStatusBar(string.Format(Resources.CharsLeftFormat, textBox.MaxLength - textBox.Text.Length));
                }

                // Create a new settings instance.
                DiggThisConfig settings = DiggThisConfig.GetInstance(SelectedContent);
                // Track the editor attributes.
                settings.Url = tbUrl.Text;
                settings.Title = tbTitle.Text;
                settings.Text = tbText.Text;
                settings.Topic = cbTopic.Text;
                settings.BkgColor = tbBkgColor.Text;
                settings.Compact = rbCompact.Checked;
                settings.TextWrapping = (rbLeft.Checked ? Alignment.Left
                    : (rbRight.Checked ? settings.TextWrapping = Alignment.Right
                        : Alignment.None));
                settings.CustomMargins = (cbMargins.SelectedIndex > 0);
                if (settings.CustomMargins)
                {
                    settings.TopMargin = (int) nudTop.Value;
                    settings.RightMargin = (int) nudRight.Value;
                    settings.BottomMargin = (int) nudBottom.Value;
                    settings.LeftMargin = (int) nudLeft.Value;
                }
                else
                {
                    nudTop.Value = settings.TopMargin = 0;
                    nudRight.Value = settings.RightMargin = 0;
                    nudBottom.Value = settings.BottomMargin = 0;
                    nudLeft.Value = settings.LeftMargin = 0;
                }
                // Show/hide the custom margins controls based on the selected item in the margins list.
                ShowCustomMargins(settings.CustomMargins);
                // Raise the changed content event.
                OnContentEdited();
            }
        }
        /// <summary>
        /// Clean up the status bar to get rid of the message indicating how many characters
        /// the user has left that can be tyoed.
        /// </summary>
        /// <param name="sender">Control causing the event.</param>
        /// <param name="e">Object containing details on the raised event.</param>
        private void TextBoxLeave(object sender, EventArgs e)
        {
            // Ensure we don't assign this event to the wrong type of control.
            Debug.Assert(sender is TextBox);
            // Simply clear the status bar.
            editorSite.UpdateStatusBar(string.Empty);
        }
        private void tbBkgColor_KeyDown(object sender, KeyEventArgs e)
        {
            // Determine if this is the first character in the string.
            // TODO: get caret location from the text box.
            if (tbBkgColor.Text.Length == 0)
            {
                // Make sure that only the pund key (#) is pressed.
                e.SuppressKeyPress = !(e.Shift && (e.KeyCode == Keys.D3));
            }
            else
            {
                switch (e.KeyCode)
                {
                    case Keys.Home:
                    case Keys.End:
                    case Keys.Back:
                    case Keys.Left:
                    case Keys.Right:
                    case Keys.Up:
                    case Keys.Down:
                    case Keys.Delete:
                        break;
                    default:
                        e.SuppressKeyPress = !(((e.KeyCode >= Keys.D0) && (e.KeyCode <= Keys.D9))
                            || ((e.KeyCode >= Keys.A) && (e.KeyCode <= Keys.F)));
                        break;
                }
            }
        }
        /// <summary>
        /// Handles selection of a background color through the Color common dialog.
        /// </summary>
        /// <param name="sender">Control causing the event.</param>
        /// <param name="e">Object containing details on the raised event.</param>
        private void btnBkgColor_Click(object sender, EventArgs e)
        {
            // Create a basic Color common dialog.
            ColorDialog dlg = new ColorDialog();
            // Set the color to that previously specified.
            dlg.Color = ColorTranslator.FromHtml(tbBkgColor.Text);
            // Only process the new color if the user indicates so.
            if (DialogResult.OK == dlg.ShowDialog(Parent))
            {
                // Set the newly selected color.
                tbBkgColor.Text = ColorUtil.ColorToHexString(dlg.Color);
            }
        }
        #endregion Form

        #endregion Event Handlers

        #region Helpers
        /// <summary>
        /// Update the controls in the editor with the values from the selected content settings.
        /// </summary>
        private void UpdateControlsWithSetting()
        {
            // Initialize the editor with the smart content properties.
            DiggThisConfig settings = DiggThisConfig.GetInstance(SelectedContent);
            tbUrl.Text = settings.Url;
            tbTitle.Text = settings.Title;
            tbText.Text = settings.Text;
            cbTopic.Text = settings.Topic;
            tbBkgColor.Text = settings.BkgColor;
            rbNormal.Checked = !settings.Compact;
            rbCompact.Checked = settings.Compact;
            rbLeft.Checked = (settings.TextWrapping == Alignment.Left);
            rbRight.Checked = (settings.TextWrapping == Alignment.Right);
            rbInline.Checked = (settings.TextWrapping == Alignment.None);
            cbMargins.SelectedIndex = (settings.CustomMargins ? 1 : 0);
            nudTop.Value = settings.TopMargin;
            nudRight.Value = settings.RightMargin;
            nudBottom.Value = settings.BottomMargin;
            nudLeft.Value = settings.LeftMargin;
            // Show/hide the custom margins controls based on the selected item in the margins list.
            ShowCustomMargins(settings.CustomMargins);
        }
        /// <summary>
        /// Tests if the given CSS color is valid.
        /// </summary>
        /// <param name="color">A string representing a CSS color in the form #000000.</param>
        /// <returns><c>true</c> if the given <c>color</c> is valid. Otherwise, <c>false</c>.</returns>
        private static bool IsValidCSSColor(string color)
        {
            // A valid CSS color is one that is maximum 7 characters and starts with
            // the pound (#) sign. The color can only have valid HEX digits.
            Regex rx = new Regex(@"\#[a-fA-F0-9]{1,6}", RegexOptions.Compiled);
            string v = rx.Match(color).Value;
            return color.Equals(v);
        }
        /// <summary>
        /// Shows/hides the custom margins controls.
        /// </summary>
        /// <param name="show"><c>true</c> to show the controls, <c>false</c> to hide them.</param>
        private void ShowCustomMargins(bool show)
        {
            lblTop.Visible = lblRight.Visible = lblBottom.Visible = lblLeft.Visible =
                nudTop.Visible = nudRight.Visible = nudBottom.Visible = nudLeft.Visible = show;
        }
        #endregion Helpers
    }
}